#include "task_cntlCenter.h"

#include "tasksInit.h"
#include "task_autoMode.h"

#include "los_task.h"
#include "los_queue.h"
#include "los_memory.h"

#include "bsp_tapeLight.h"
#include "bsp_e53.h"
#include "bsp_gpioDev.h"

void task_cntlCenter(void);

unsigned int task_cntlCenter_id;
TSK_INIT_PARAM_S task_cntlCenter_handler = {
    (TSK_ENTRY_FUNC)task_cntlCenter,
    25,
    0,
    1280,
    "task_cntlCenter",
    0
};

#define MAX_CNTL_DEV_NUM       32

typedef struct CntlDev cntl_dev_t;

typedef int(*cntl_func_t)(cntl_dev_t* self, void* param);

struct CntlDev
{
    int id;
    char* name;
    // int name_size;  //包括\0

    void* spec;     //特别的结构体
    // void* param;    //控制函数的参数
    // int (*cntl_func)(cntl_dev_t* self, void* param);
    cntl_func_t cntl_func;
};

cntl_dev_t* cntl_unit[MAX_CNTL_DEV_NUM];
int unit_tail = 0;   //指向数组右边空位

int cntl_func_for_tapeLight(cntl_dev_t* self, void* param);
int cntl_func_for_tableLamp(cntl_dev_t* self, void* param);
int cntl_func_for_alarmClock(cntl_dev_t* self, void* param);
int cntl_func_for_gpioDev(cntl_dev_t* self, void* param);

//具体设备实例
cntl_dev_t dev_masterBedroom_tapeLight = {
    .name = "masterBedroom_tapeLight",
    .spec = (void *)&light_masterBedroom,
    .cntl_func = (cntl_func_t)cntl_func_for_tapeLight
},
dev_livingRoom_tapeLight = {
    .name = "livingRoom_tapeLight",
    .spec = (void *)&light_livingRoom,
    .cntl_func = (cntl_func_t)cntl_func_for_tapeLight
},
dev_kitchen_tapeLight = {
    .name = "kitchen_tapeLight",
    .spec = (void *)&light_kitchen,
    .cntl_func = (cntl_func_t)cntl_func_for_tapeLight
},
dev_masterBedroom_tableLamp = {
    .name = "masterBedroom_tableLamp",
    .spec = NULL,
    .cntl_func = (cntl_func_t)cntl_func_for_tableLamp
},
dev_masterBedroom_alarmClock = {
    .name = "masterBedroom_alarmClock",
    .spec = NULL,
    .cntl_func = (cntl_func_t)cntl_func_for_alarmClock
},
dev_masterBedroom_airConditioner = {
    .name = "masterBedroom_airConditioner",
    .spec = (void*)&fan_masterBedroom,
    .cntl_func = (cntl_func_t)cntl_func_for_gpioDev
},
dev_kitchen_hood = {
    .name = "kitchen_hood",
    .spec = (void*)&fan_kitchen,
    .cntl_func = (cntl_func_t)cntl_func_for_gpioDev
},
dev_livingRoom_curtain = {
    .name = "livingRoom_curtain",
    .spec = (void*)&curtain_livingRoom,
    .cntl_func = (cntl_func_t)cntl_func_for_gpioDev
},
dev_masterBedroom_humidifier = {
    .name = "masterBedroom_humidifier",
    .spec = (void*)&humidifier_masterBedroom,
    .cntl_func = (cntl_func_t)cntl_func_for_gpioDev
};
//...
;


static int cntl_dev_register(cntl_dev_t* new_dev);
static int get_id_by_name(const char* name);

void task_cntlCenter(void)
{
    // 等待硬件初始化完成
    LOS_EventRead(&bspInit_ECB, BSPINIT_EVENT_INITOK, LOS_WAITMODE_AND, LOS_WAIT_FOREVER);

    cntl_msg_t msg;
    uint32_t msg_len = sizeof(msg);
    int ret = 0;

    //先注册cntl_dev
    cntl_dev_register(&dev_masterBedroom_tapeLight);
    cntl_dev_register(&dev_livingRoom_tapeLight);
    cntl_dev_register(&dev_kitchen_tapeLight);
    cntl_dev_register(&dev_masterBedroom_tableLamp);
    cntl_dev_register(&dev_masterBedroom_alarmClock);
    cntl_dev_register(&dev_masterBedroom_airConditioner);
    cntl_dev_register(&dev_kitchen_hood);
    cntl_dev_register(&dev_livingRoom_curtain);
    cntl_dev_register(&dev_masterBedroom_humidifier);

    while(1)
    {
        //读队列,查看控制消息
        ret = LOS_QueueReadCopy(cntlCenter_qId, &msg, &msg_len, LOS_WAIT_FOREVER);
        if(ret != 0)
        {
            printf("[task cntlCenter] LOS_QueueReadCopy error, ret: 0x%x\n", ret);  //warnning 
            continue;
        }

        cntl_dev_t* cur_dev = NULL;
        int id = -1;  
        int param = 0;

        switch(msg.type)
        {
        case CNTL_MSG_TYPE_NAME:
                      

            id = get_id_by_name(msg.name);  //获取id
            if(id < 0)
            {
                printf("[task cntlCenter] cntl_msg name match failed.\n");  //warnning
                continue;
            }

            //写模式转换队列，转换成手动模式
            event_mode_switch_t autoMode_event = EVENT_MODE_SWITCH_TO_MANUAL;
            LOS_QueueWriteCopy(autoMode_qId, &autoMode_event, sizeof(autoMode_event), 1);

            //执行相应操作函数
            cur_dev = cntl_unit[id];
            printf("[task cntlCenter] cur_dev id: %d, name: %s.\n", cur_dev->id, cur_dev->name);

            ret = (cur_dev->cntl_func)(cur_dev, msg.param);
            if(ret != 0)
            {
                printf("[task cntlCenter] exec cntl_func error, cntl_dev id: %d, name: %s.\n", id, cur_dev->name);
            }

            //释放空间
            LOS_MemFree(OS_SYS_MEM_ADDR, msg.name);
            LOS_MemFree(OS_SYS_MEM_ADDR, msg.param);

            break;

        case CNTL_MSG_TYPE_ID:
            if(msg.id < 0 || msg.id >= unit_tail)
            {
                printf("[task cntlCenter] id: %d is out of range.\n", msg.id);
                continue;
            }

            cur_dev = cntl_unit[msg.id];

            printf("[task cntlCenter] cntl type id :%d, name: %s\n", cur_dev->id, cur_dev->name);

            ret = (cur_dev->cntl_func)(cur_dev, msg.param);
            if(ret != 0)
            {
                printf("[task cntlCenter] exec cntl_func error, cntl_dev id: %d, name: %s.\n", id, cur_dev->name);
            }
            LOS_MemFree(OS_SYS_MEM_ADDR, msg.param);
            break;

        case CNTL_MSG_TYPE_CLOSE_ALL:
            
            printf("[task cntlCenter] cntl msg close all.\n");

            for(int i = 0; i < unit_tail; i++)
            {
                ret = (cntl_unit[i]->cntl_func)(cntl_unit[i], (void *)&param);
                if(ret != 0)
                {
                    printf("[task cntlCenter] exec cntl_func error, cntl_dev id: %d, name: %s.\n", i, cntl_unit[i]->name);
                }
            }
            break;

        default:
            break;
        }
        // //查看来源，填相应队列
        // if(MSG_FROM_MQTT == msg.source)
        // {
        //     //事件为
        //     LOS_QueueWriteCopy();
        // }

        
    }
}

int cntl_func_for_gpioDev(cntl_dev_t* self, void* param)
{
    if(NULL == self || NULL == param)
        return -1;

    gpioDev_set_state(self->spec, *(int*)param);

    return 0;
}

int cntl_func_for_tapeLight(cntl_dev_t* self, void* param)
{
    int ret = 0;

    if(NULL == self || NULL == param)
        return -1;

    ret = tapeLight_set_lightValue(self->spec, *(int *)param);
    if(ret != 0)
        return -2;

    return 0;
}

int cntl_func_for_tableLamp(cntl_dev_t* self, void* param)
{
    if(NULL == self || NULL == param)
        return -1;

    light_set(*(int *)param);

    return 0;
}

int cntl_func_for_alarmClock(cntl_dev_t* self, void* param)
{
    if(NULL == self || NULL == param)
        return -1;

    motor_set(*(int *)param);

    return 0;
}

// TODO: 可优化成 hash 表
static int get_id_by_name(const char* name)
{
    int id = -1;
    int i = 0;

    if(NULL == name)
        return -2;

    // strcmp() == 0
    for(i = 0; i < unit_tail; i++)
    {
        if(strcmp(name, cntl_unit[i]->name) == 0)
        {
            id = i;
            break;
        }
    }

    return id;
}

static int cntl_dev_register(cntl_dev_t* new_dev)
{
    if(NULL == new_dev)
        return -1;

    //找空位
    // for(int i = 0; i < MAX_CNTL_DEV_NUM && cntl_unit[i] != NULL; i++);

    if(unit_tail >= MAX_CNTL_DEV_NUM)
    {
        printf("[cntl_dev_register] cntl_unit is full.\n");
        return -2;  //没空位了
    }

    new_dev->id = unit_tail;
    cntl_unit[unit_tail] = new_dev;
    unit_tail++;

    return 0;
}
